import {type GLTF, GLTFLoader} from "three/examples/jsm/loaders/GLTFLoader";
import {LoadingManager, Scene, Texture, TextureLoader} from "three";
import {ModelInstanceStore} from "./ModelInstanceStore.ts";
import {ModelLoadable} from "./model/ModelLoadable.ts";
import type {Model} from "./model/Model.ts";
import {texture} from "three/src/Three.TSL";

export class Loader {

    manager: LoadingManager
    gltfLoader: GLTFLoader
    textureLoader: GLTFLoader

    afterLoadComplete: ()=>void

    private readonly modelStore: ModelInstanceStore

    constructor(onCompleted: () => void) {
        this.afterLoadComplete = onCompleted
        this.modelStore = new ModelInstanceStore()
        this.manager = new LoadingManager()

        this.manager.onStart = (source: string, loaded: number, total: number) => {
            console.log("on_start", source, loaded, total)
        }
        this.manager.onLoad = () => {
            console.log('load completed')
            if (onCompleted) {
                onCompleted()
            }
        }
        this.manager.onProgress = (source: string, loaded: number, total: number) => {
            console.log('progress', loaded+"/"+total, source)
        }
        this.manager.onError = (source) => {
            console.log("load",source, "fail")
        }

        this.gltfLoader = new GLTFLoader(this.manager)
        this.textureLoader = new TextureLoader(this.manager)
    }

    getStore(): ModelInstanceStore {
        return this.modelStore
    }

    load(m: Model):boolean {
        let loadable = false
        if (m instanceof ModelLoadable) {
            loadable = true
            let model = m as ModelLoadable
            let category = model.modelCategory
            switch (category) {
                case 'gltf':
                    console.log('load gltf', model.source)
                    this.loadGltf(model.source, (obj: GLTF) => {
                        model.onLoad(obj.scene)
                    })
                    break
            case 'texture':
                console.log('load texture', model.source)
                this.loadTexture(model.source, (obj: Texture) => {
                    this.getStore().addTexture(model.modelName, obj)
                })
                break
            }
        }
        return loadable
    }

    loadModels() {
        let res = this.modelStore.getModels()
        let hasLoadable = false

        for (const [name, model] of res.entries()) {
            console.log("model:", name)
            let loadable = this.load(model)
            if (loadable) {
                hasLoadable = loadable
            }
        }
        if (!hasLoadable) { // 无加载类型
            if (this.afterLoadComplete) {
                this.afterLoadComplete()
            }
        }
    }

    loadGltf(source: string, h:(obj:GLTF)=>void) {
        this.gltfLoader.load(source, (gltf: GLTF) => {
            // console.log("加载gltf模型", source)
            // console.log(gltf)
            if (h) {
                h(gltf)
            }
        })
    }

    loadTexture(source: string, h:(obj:Texture)=>void):void {
        this.textureLoader.load(source, (texture: Texture) => {
            if (h) {
                h(texture)
            }
        })
    }
}